package com.golxen.framework.user.player;

import com.golxen.framework.activity.ActivityModule;
import com.golxen.framework.event.BaseEventArg;
import com.golxen.framework.event.condition.ConditionModule;
import com.golxen.framework.event.eGamePlayerEventType;
import com.golxen.framework.user.UserMgr;
import com.google.protobuf.AbstractMessage.Builder;
import com.golxen.framework.PBPacket.PBPacket;
import com.golxen.framework.PBPacket.PBPacketUtils;
import com.golxen.framework.module.AbstractModule;
import com.golxen.framework.common.queue.AutoMQ;
import com.golxen.framework.common.queue.PlayerMQ;
import com.golxen.framework.executor.ThreadPlugin;
import com.golxen.framework.module.ModulePlugin;
import com.golxen.framework.user.dao.entity.UserInfo;
import com.golxen.utils.LogUtil;
import com.golxen.utils.TimeUtils;
import com.mysql.cj.util.StringUtils;
import org.slf4j.Logger;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class GamePlayer implements PlayerMQ {

    protected static Logger log = LogUtil.COMMON;

    private String ip;

    private String webSocketIp = "";

    private UserInfo userInfo;

    private String deviceId = "";

    private short state;// 玩家当前状态
    /**
     * 玩家最后一次ping的时间
     */
    private long lastPingTime;
    /**
     * 失去心跳次数
     */
    private int loseHeartTimes;

    private String k = "";
    private int rec = 0;
    private int send = 0;

    protected Map<Class<?>, AbstractModule> moduleMap = new LinkedHashMap<Class<?>, AbstractModule>();

    protected List<AbstractModule> moduleList = new ArrayList<AbstractModule>();

    private final AutoMQ<Runnable> cmdQueue = new AutoMQ<Runnable>(
            ThreadPlugin.getServerCommandExecutor());


    public int getRec() {
        return rec;
    }

    public void setRec(int rec) {
        this.rec = rec;
    }

    public int getSend() {
        return send;
    }

    public void setSend(int send) {
        this.send = send;
    }

    public String getK() {
        return k;
    }

    public void setK(String k) {
        this.k = k;
    }

    public GamePlayer(UserInfo userInfo) {
        this.userInfo = userInfo;
        UserMgr.setUserInfo(userInfo);
        this.lastPingTime = System.currentTimeMillis();
        initModule();
    }

    private void initModule() {
        List<Class<?>> moduleClsList = ModulePlugin.getModuleClsList();
        for (Class<?> class1 : moduleClsList) {
            try {
                Constructor<?> constructor = class1.getConstructor(GamePlayer.class);
                AbstractModule newInstance = (AbstractModule) constructor.newInstance(this);
                addModule(newInstance);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }


    public void addModule(AbstractModule module) {
        moduleList.add(module);

        moduleMap.put(module.getModuleType(), module);
        if (!moduleMap.containsKey(module.getClass())) {
            moduleMap.put(module.getClass(), module);
        }
    }

    public List<AbstractModule> getModuleList() {
        return moduleList;
    }

    @Override
    public AutoMQ<Runnable> getCommandQueue() {
        return cmdQueue;
    }

    public boolean loadDB() {
        for (AbstractModule module : getModuleList()) {
            try {
                module.loadDB();
            } catch (Exception e) {
                log.error(module.getClass().getName(), e);
                return false;
            }
        }
        return true;
    }

    public void afterLoadDB() {
        for (AbstractModule module : getModuleList()) {
            try {
                module.afterLoadDB();
            } catch (Exception e) {
                log.error(module.getClass().getName(), e);
            }
        }
    }

    public void save() {
        for (AbstractModule module : getModuleList()) {
            try {
                long begin;
                long cost;
                synchronized (module.getSaveLockObj()) {// 加锁，单次执行
                    begin = System.currentTimeMillis();
                    module.saveDB();
                    cost = System.currentTimeMillis() - begin;
                }
                if (cost > 100) {
                    long userId = 0;
                    if (null != userInfo) {
                        userId = userInfo.getUserId();
                    }
                    log.warn("save too long time, userId {}, module: {} , cost : {}", userId,
                            module.getModuleType().getSimpleName(), cost);
                }
            } catch (Exception e) {
                log.error("{} saveDb error {}", getUserId(), module.getClass().getSimpleName(), e);
            }
        }
    }

    @SuppressWarnings("unchecked")
    public <T> T getModule(Class<T> T) {
        AbstractModule baseModule = moduleMap.get(T);
        if (baseModule == null) {
            log.error("{} no init module: {}", getUserId(), T.getName());
        }
        return (T) baseModule;
    }


    public void resetDay() {

        long zeroTime = TimeUtils.getZeroTimeTimeStamp() / 1000;
        long lastLoginTime = getUserInfo().getLastLoginTime();
        if ((System.currentTimeMillis() / 1000 - lastLoginTime) > 24 * 3600) {
            getUserInfo().setLastLoginTime(zeroTime);
        }else {
            return;
        }

        for (AbstractModule absGeneralModule : moduleList) {
            try {
                absGeneralModule.resetDay();
            } catch (Exception e) {
                log.error("", e);
            }
        }

        // 同步活动数据
        getModule(ActivityModule.class).syncActivity();
        notifyListener(eGamePlayerEventType.LoginDays.getValue(), 1);



        log.debug("reset.day.{} reset day complete...", getUserId());
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        if (StringUtils.isNullOrEmpty(this.ip)) {
            this.ip = ip;
        }
    }

    public String getWebSocketIp() {
        return webSocketIp;
    }

    public void setWebSocketIp(String webSocketIp) {
        if (StringUtils.isNullOrEmpty(webSocketIp)) {
            return;
        }
        this.webSocketIp = webSocketIp;
    }

    public long getUserId() {
        if (null != userInfo) {
            return userInfo.getUserId();
        }
        return 0;
    }


    public UserInfo getUserInfo() {
        return userInfo;
    }

    public short getState() {
        return state;
    }

    public void setState(short state) {
        this.state = state;
    }




    public long getLastPingTime() {
        return lastPingTime;
    }

    public void setLastPingTime(long lastPingTime) {
        this.lastPingTime = lastPingTime;
        this.loseHeartTimes = 0;
    }

    public int getLoseHeartTimes() {
        return loseHeartTimes;
    }

    public void setLoseHeartTimes(int loseHeartTimes) {
        this.loseHeartTimes = loseHeartTimes;
    }


    /**
     * 发送给客户端提示
     */
    public void sendMessage(String key) {

    }


    public void sendPacket(int code, Builder<?> messageBuilder) {
        PBPacket pkg = PBPacketUtils.buildMessage(code, messageBuilder);
        sendPacket(pkg);
    }

    public PBPacket getPacketMsg(int code, Builder<?> messageBuilder) {
        PBPacket pkg = PBPacketUtils.buildMessage(code, messageBuilder);
        return pkg;
    }

    public void sendPacket(PBPacket message) {
        GamePlayerMgr.sendPacket(this, message);
    }

    public void sendLoginMessage() {
        for (AbstractModule module : getModuleList()) {
            try {
                module.loginSendMsg();
            } catch (Exception e) {
                log.error(module.getClass().getName(), e);
            }
        }
    }



    /**
     * 登录之后执行的逻辑
     */
    public void afterLogin() {
        for (AbstractModule module : getModuleList()) {
            try {
                module.afterLogin();
            } catch (Exception e) {
                log.error(module.getClass().getName(), e);
            }
        }
    }

    long lastRequestTime;

    /**
     * 是否访问过快
     * 
     * @return
     */
    public boolean isRequestToFast() {
        long nowTime = System.currentTimeMillis();
        boolean stat = false;
        if (nowTime - lastRequestTime <= 500) {
            stat = true;
        }
        lastRequestTime = nowTime;
        return stat;
    }

    /**
     * 通知监听器执行任务
     */
    public void notifyListener(int eventType, Object object) {
        getModule(ConditionModule.class).getGamePlayerEvent().notifyListener(eventType, new BaseEventArg(object, eventType));
    }


}
